/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.stx.xhb.customwaterview.components;

import com.stx.xhb.customwaterview.ResourceTable;
import com.stx.xhb.customwaterview.model.WaterModel;
import com.stx.xhb.customwaterview.model.WaterViewTag;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.StackLayout;
import ohos.agp.components.Text;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;

import static ohos.agp.animation.Animator.INFINITE;

/**
 * 支付宝蚂蚁森林水滴能量
 *
 * @since 2021-06-08
 */
public class WaterFlake extends StackLayout implements Component.EstimateSizeListener,
        Component.BindStateChangedListener {
    private static final int WHAT_ADD_PROGRESS = 1;
    private OnWaterItemListener mOnWaterItemListener;
    /**
     * 小树坐标X
     */
    private float treeCenterX = 0;
    /**
     * 小树坐标Y
     */
    private float treeCenterY = 0;
    /**
     * 是否正在收集能量
     */
    private boolean isCollect = false;

    /**
     * 控制水滴动画的偏移量
     */
    private final List<Float> mOffsets = Arrays.asList(5.0f, 4.5f, 4.8f, 5.5f, 5.8f, 6.0f, 6.5f);
    private SecureRandom mRandom = new SecureRandom();
    private float mWidth;
    private float mHeight;
    private LayoutScatter mLayoutInflater;

    private List<WaterModel> mModelList;

    /**
     * WaterFlake
     *
     * @param context
     */
    public WaterFlake(Context context) {
        this(context, null);
    }

    /**
     * WaterFlake
     *
     * @param context
     * @param attrs
     */
    public WaterFlake(Context context, AttrSet attrs) {
        this(context, attrs, "");
    }

    /**
     * WaterFlake
     *
     * @param context
     * @param attrs
     * @param styleId
     */
    public WaterFlake(Context context, AttrSet attrs, String styleId) {
        super(context, attrs, styleId);
        init();
    }

    private void init() {
        mLayoutInflater = LayoutScatter.getInstance(getContext());
        setBindStateChangedListener(this);
        setEstimateSizeListener(this);
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        startShow();
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
    }

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        mWidth = Component.EstimateSpec.getSize(widthEstimateConfig);
        mHeight = Component.EstimateSpec.getSize(heightEstimateConfig);
        return false;
    }

    /**
     * 设置小球数据，根据数据集合创建小球数量
     *
     * @param modelList 数据集合
     */
    public void setModelList(final List<WaterModel> modelList) {
        mModelList = modelList;
    }

    /**
     * 设置小球数据，根据数据集合创建小球数量
     *
     * @param modelList 数据集合
     * @param treeX     收集动画结束的x坐标
     * @param treeY     收集动画结束的y坐标
     */
    public void setModelList(final List<WaterModel> modelList, float treeX, float treeY) {
        if (modelList == null || modelList.isEmpty()) {
            return;
        }
        this.treeCenterX = treeX;
        this.treeCenterY = treeY;
        mModelList = modelList;
    }

    /**
     * 更新收集动画结束点的位置
     *
     * @param treeX 横坐标
     * @param treeY 纵坐标
     */
    public void updateCollectionPosition(float treeX, float treeY) {
        this.treeCenterX = treeX;
        this.treeCenterY = treeY;
    }

    private void startShow() {
        removeAllComponents();
        if (mModelList == null) {
            return;
        }
        new EventHandler(EventRunner.getMainEventRunner())
                .postTask(() -> {
                    final int max = 7;
                    int[] randomX = randomCommon(1, max, mModelList.size());
                    int[] randomY = randomCommon(1, max, mModelList.size());
                    if (randomX == null || randomY == null) {
                        return;
                    }
                    for (int idx = 0; idx < mModelList.size(); idx++) {
                        final Component view = mLayoutInflater.parse(ResourceTable.Layout_item_water, this, false);
                        Text text = (Text) view.findComponentById(ResourceTable.Id_text);
                        text.setText(mModelList.get(idx).getContent());
                        final float scx = 0.11f;
                        final float scy = 0.09f;
                        view.setContentPositionX((float) ((mWidth * randomX[idx] * scx)));
                        view.setContentPositionY((float) ((mHeight * randomY[idx] * scy)));
                        WaterModel waterModel = mModelList.get(idx);
                        view.setClickedListener(new ClickedListener() {
                            @Override
                            public void onClick(Component component) {
                                if (isCollect) {
                                    return;
                                }
                                if (mOnWaterItemListener != null) {
                                    mOnWaterItemListener.onItemClick(waterModel);
                                    collectAnimator(view);
                                }
                            }
                        });
                        float offset = mOffsets.get(mRandom.nextInt(mOffsets.size()));
                        final float off = 1.5f;
                        WaterViewTag tag = new WaterViewTag(mRandom.nextBoolean(), offset * off);
                        view.setTag(tag);

                        addComponent(view);
                        addShowViewAnimation(view);
                        start(view);
                    }
                });
    }

    /**
     * 设置小球点击事件
     *
     * @param onWaterItemListener
     */
    public void setOnWaterItemListener(OnWaterItemListener onWaterItemListener) {
        mOnWaterItemListener = onWaterItemListener;
    }

    /**
     * OnWaterItemListener
     *
     * @since 2021-06-08
     */
    public interface OnWaterItemListener {
        /**
         * onItemClick
         *
         * @param waterModel
         */
        void onItemClick(WaterModel waterModel);
    }

    private void collectAnimator(final Component view) {
        if (isCollect) {
            return;
        }
        isCollect = true;
        AnimatorProperty animatorProperty = view.createAnimatorProperty();
        final int duration = 2000;
        animatorProperty.moveFromX(view.getContentPositionX()).moveToX(getTreeCenterX())
                .moveFromY(view.getContentPositionY()).moveToY(getTreeCenterY())
                .alpha(0)
                .setLoopedCount(0)
                .setCurveType(Animator.CurveType.LINEAR)
                .setDuration(duration)
                .setStateChangedListener(new Animator.StateChangedListener() {
                    @Override
                    public void onStart(Animator animator) {
                    }

                    @Override
                    public void onStop(Animator animator) {
                    }

                    @Override
                    public void onCancel(Animator animator) {
                    }

                    @Override
                    public void onEnd(Animator animator) {
                        removeComponent(view);
                        isCollect = false;
                    }

                    @Override
                    public void onPause(Animator animator) {
                    }

                    @Override
                    public void onResume(Animator animator) {
                    }
                }).start();
    }

    private void start(Component view) {
        WaterViewTag tag = (WaterViewTag) view.getTag();
        boolean isUp = tag.isUp();
        float offset = tag.getOffset();
        AnimatorProperty mAnimator = null;
        float transY = view.getTop() + view.getTranslationY();
        if (isUp) {
            mAnimator = createAnimatorProperty().moveFromY(transY - offset).moveToY(transY + offset);
        } else {
            mAnimator = createAnimatorProperty().moveFromY(transY + offset).moveToY(transY - offset);
        }
        final int duration = 2000;
        mAnimator.setDuration(duration).setCurveType(Animator.CurveType.CYCLE)
                .setLoopedCount(INFINITE);
        mAnimator.start();
    }

    /**
     * 添加显示动画
     *
     * @param view
     */
    private void addShowViewAnimation(Component view) {
        view.setAlpha(0);
        view.setScaleX(0);
        view.setScaleY(0);
        final int duration = 500;
        view.createAnimatorProperty().alpha(1).scaleX(1).scaleY(1).setDuration(duration).start();
    }

    /**
     * 刷新view
     */
    public void resetComponent() {
        startShow();
    }

    /**
     * 随机指定范围内N个不重复的数
     * 最简单最基本的方法
     *
     * @param min    指定范围最小值
     * @param max    指定范围最大值
     * @param lenght 随机数个数
     * @return N个不重复的数
     */
    public static int[] randomCommon(int min, int max, int lenght) {
        int[] result = new int[lenght];
        if (lenght > (max - min + 1) || max < min) {
            return result;
        }
        int count = 0;
        while (count < lenght) {
            int num = (int) ((new SecureRandom().nextDouble() * (max - min)) + min);
            boolean isFlag = true;
            for (int index = 0; index < lenght; index++) {
                if (num == result[index]) {
                    isFlag = false;
                    break;
                }
            }
            if (isFlag) {
                result[count] = num;
                count++;
            }
        }
        return result;
    }

    public float getTreeCenterX() {
        return treeCenterX;
    }

    public float getTreeCenterY() {
        return treeCenterY;
    }
}
